using System.Security.Cryptography;
using SixLabors.Fonts;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Drawing.Processing;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;

namespace net_work.Common.Utils;

public static class CaptchaUtils
{
    private static readonly Font TextFont = new FontCollection().AddSystemFonts().Get("Arial").CreateFont(24);

    /// <summary>
    /// 生成随机验证码
    /// </summary>
    /// <param name="length">验证码长度</param>
    /// <returns>随机验证码</returns>
    public static string GenerateRandomCode(int length)
    {
        const string chars = "ABCDEFGHJKMNPQRSTUVWXYZabcdefghjkmnpqrstuvwxyz123456789";
        using var rng = RandomNumberGenerator.Create();
        var buffer = new byte[length];
        rng.GetBytes(buffer);
        return new string(buffer.Select(b => chars[b % chars.Length]).ToArray());
    }

    /// <summary>
    /// 生成验证码图片
    /// </summary>
    /// <param name="captchaCode">验证码</param>
    /// <returns>图片字节数组</returns>
    public static byte[] GenerateCaptchaImage(string captchaCode)
    {
        const int width = 150;
        const int height = 50;
        using var image = new Image<Rgba32>(width, height);
        var random = new Random();

        image.Mutate(ctx =>
        {
            ctx.Fill(Color.White);

            for (var i = 0; i < captchaCode.Length; i++)
            {
                ctx.DrawText(captchaCode[i].ToString(), TextFont, Color.Black,
                    new PointF(10 + i * 25, 10 + random.Next(-5, 5)));
            }

            AddNoiseLines(ctx, width, height);
        });

        using var ms = new MemoryStream();
        image.SaveAsPng(ms);
        return ms.ToArray();
    }

    /// <summary>
    /// 添加干扰线
    /// </summary>
    /// <param name="ctx">图像处理上下文</param>
    /// <param name="width">图像宽度</param>
    /// <param name="height">图像高度</param>
    private static void AddNoiseLines(IImageProcessingContext ctx, int width, int height)
    {
        var random = new Random();
        for (var i = 0; i < 5; i++)
        {
            var x1 = random.Next(0, width);
            var y1 = random.Next(0, height);
            var x2 = random.Next(0, width);
            var y2 = random.Next(0, height);
            ctx.DrawLine(Color.Gray, 1, new PointF(x1, y1), new PointF(x2, y2));
        }
    }
}